package com.app.brilliant.game.service.impl;

import com.app.brilliant.common.api.ApiCode;
import com.app.brilliant.common.api.ApiResult;
import com.app.brilliant.common.enums.StateEnum;
import com.app.brilliant.common.service.impl.BaseServiceImpl;
import com.app.brilliant.common.vo.PageContainer;
import com.app.brilliant.game.convert.AppUserConvert;
import com.app.brilliant.game.mapper.WxConfigMapper;
import com.app.brilliant.game.mapper.WxUserMapper;
import com.app.brilliant.game.bean.WxUser;
import com.app.brilliant.game.param.WxLoginParam;
import com.app.brilliant.game.response.WxUserListInfo;
import com.app.brilliant.game.response.WxUserLoginRes;
import com.app.brilliant.game.service.WxUserService;
import com.app.brilliant.shiro.cache.LoginRedisService;
import com.app.brilliant.shiro.jwt.JwtProperties;
import com.app.brilliant.shiro.jwt.JwtToken;
import com.app.brilliant.shiro.util.JwtUtil;
import com.app.brilliant.shiro.util.SaltUtil;
import com.app.brilliant.shiro.vo.app.LoginAppUserRedisVo;
import com.app.brilliant.sign.constant.Constants;
import com.app.brilliant.sys.params.WxUserListPageParam;
import com.app.brilliant.util.PasswordUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import weixin.popular.api.SnsAPI;
import weixin.popular.bean.sns.Jscode2sessionResult;
import weixin.popular.bean.sns.SnsToken;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author GF
 * @description 针对表【wx_user】的数据库操作Service实现
 * @createDate 2025-07-25 10:21:53
 */
@Service
public class WxUserServiceImpl extends BaseServiceImpl<WxUserMapper, WxUser> implements WxUserService {
    @Autowired
    private WxConfigMapper wxConfigMapper;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private LoginRedisService loginRedisService;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public ApiResult loginWx(WxLoginParam wxLoginParam) {
        String appid = wxConfigMapper.selectByKey(Constants.NomalConfigKey.appid);
        String secret = wxConfigMapper.selectByKey(Constants.NomalConfigKey.secret);
        Jscode2sessionResult sessionResult = SnsAPI.jscode2session(appid, secret, wxLoginParam.getCode());
        if (sessionResult.isSuccess()) {
            WxUser userInfo = wxUserMapper.selectByOpenid(sessionResult.getOpenid());
            if (userInfo == null) {
                SnsToken snsToken = SnsAPI.oauth2AccessToken(appid, secret, wxLoginParam.getCode());
                weixin.popular.bean.user.User user = SnsAPI.userinfo(snsToken.getAccess_token(),
                        sessionResult.getOpenid(), "zh_cn");
                userInfo = new WxUser();
                userInfo.setUserName(user.getNickname());
                userInfo.setOpenId(user.getOpenid());
                userInfo.setUnionId(user.getUnionid());
                userInfo.setAvatarUrl(user.getHeadimgurl());
                save(userInfo);
            }
            if (userInfo.getState().intValue() == StateEnum.DISABLE.getCode()) {
                return ApiResult.fail(ApiCode.FAIL, "账号已禁用");
            }
            JwtToken jwtToken = getJwtToken(userInfo);
            String token = jwtToken.getToken();
            WxUserLoginRes wxUserLoginRes = new WxUserLoginRes();
            wxUserLoginRes.setToken(token);
            wxUserLoginRes.setAvatarUrl(userInfo.getAvatarUrl());
            return ApiResult.ok(wxUserLoginRes);
        }
        return ApiResult.fail(ApiCode.FAIL, sessionResult);
    }



    @Override
    public PageContainer<WxUserListInfo> wxUserList(WxUserListPageParam wxUserListPageParam) {
        Page page = setPageParam(wxUserListPageParam);
        return PageContainer.of(baseMapper.wxUserList(page, wxUserListPageParam));
    }

    @Override
    public boolean changeAppUserState(Integer uid, Integer state) {
        WxUser wxUser = getById(uid);
        wxUser.setState(state);
        if (state.intValue() == StateEnum.DISABLE.getCode()) {
            loginRedisService.deleteAppUserAllCache(wxUser.getId() + "");
        }
        return updateById(wxUser);
    }

    @Override
    public Map<String, Object> loginByEmail(String email, String password) {
        // 查询用户信息
        WxUser wxUser = wxUserMapper.selectOne(new QueryWrapper<WxUser>().eq("email", email));
        if (wxUser == null) {
            throw new RuntimeException("用户不存在");
        }
        if (StateEnum.DISABLE.getCode().equals(wxUser.getState())) {
            throw new RuntimeException("账号已禁用");
        }

        // 校验密码
        String encryptPassword = PasswordUtil.encrypt(password, wxUser.getSalt());
        if (!encryptPassword.equals(wxUser.getPass())) {
            throw new RuntimeException("密码错误");
        }

        // 生成Token
        JwtToken token = getJwtToken(wxUser);

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token.getToken());
        result.put("user", wxUser);
        return result;
    }

    protected JwtToken getJwtToken(WxUser gameUser) {
        LoginAppUserRedisVo loginAppUserRedisVo = AppUserConvert.INSTANCE.appUserToLoginAppUserVo(gameUser);
        // 获取数据库中保存的盐值
        String newSalt = SaltUtil.getSalt(loginAppUserRedisVo.getSalt(), jwtProperties);
        // 生成token字符串并返回
        Long expireSecond = jwtProperties.getExpireSecond();
        String token = JwtUtil.generateToken("app", gameUser.getId() + "", newSalt, Duration.ofSeconds(expireSecond));
        // 创建AuthenticationToken
        JwtToken jwtToken = JwtToken.build("app", token, gameUser.getId() + "", newSalt, expireSecond);
        loginRedisService.cacheLoginInfo(jwtToken, loginAppUserRedisVo);
        return jwtToken;
    }

    @Override
    public WxUser getByOpenId(String openId) {
        return wxUserMapper.selectByOpenid(openId);
    }

    @Override
    public boolean existsByEmail(String email) {
        return wxUserMapper.existsByEmail(email) > 0;
    }

    @Override
    public boolean resetPasswordByEmail(String email, String newPassword, String verificationCode) {
        // 验证邮箱是否存在
        if (!existsByEmail(email)) {
            throw new RuntimeException("邮箱未注册");
        }

        // 验证验证码（此处需替换为实际的验证码验证逻辑）
        if (!verifyVerificationCode(email, verificationCode,Constants.NomalRedisKey.forgetAppUserEmailKey)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 更新密码
        int updatedRows = wxUserMapper.updatePasswordByEmail(email, newPassword);
        return updatedRows > 0;
    }

    @Override
    @Transactional
    public boolean registerWxUserByEmail(String email, String password) {
        // 创建用户
        WxUser user = new WxUser();
        user.setEmail(email);
        user.setCreateTime(new Date());
        user.setState(StateEnum.ENABLE.getCode());
        user.setUserName(email);
        save(user);
        JwtToken jwtToken = getJwtToken(user);
        user.setSalt(jwtToken.getSalt());
        String encryptPassword = PasswordUtil.encrypt(password, user.getSalt());
        user.setPass(encryptPassword);
        return updateById(user);
    }

    private boolean verifyVerificationCode(String email, String verificationCode,String key) {
        // 验证验证码
        String redisKey = String.format(key, email);
        Object cached = redisTemplate.opsForValue().get(redisKey);
        if (cached == null || !verificationCode.equals(cached.toString())) {
            throw new RuntimeException("验证码错误或已过期");
        }
        // 验证码一次性，验证后删除
        redisTemplate.delete(redisKey);
        return true;
    }
}
